package route

import (
    "errors"
    "fcs-api/src/app/model"
    "fcs-api/src/app/service/ksvc"
    k8s "fcs-api/src/client/kubernetes"
    "fmt"
    "reflect"
    "strings"

    "git.inspur.com/x/common/loggerfactory"
    metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    kapiV1 "knative.dev/serving/pkg/apis/serving/v1"
)

var logger = loggerfactory.GetLogger()

func CreateRoute(fcClient *k8s.FcClient, alias *model.FuncAlias) (*kapiV1.Route, error) {

    namespace := ksvc.GetAliasNamespace(alias.AccountId, alias.GroupName)
    traffic, err := getTraffic(fcClient, alias)
    if err != nil {
        return nil, err
    }
    route := &kapiV1.Route{
        TypeMeta: metaV1.TypeMeta{
            Kind:       "Route",
            APIVersion: "serving.knative.dev/v1",
        },
        ObjectMeta: metaV1.ObjectMeta{
            Name: alias.FuncName + "-" + alias.AliasName,
            // 添加函数名称label，删除的时候使用这个label作为筛选条件进行删除
            Labels: map[string]string{
                "function": alias.FuncName,
            },
        },
        Spec: kapiV1.RouteSpec{
            Traffic: traffic,
        },
    }
    return fcClient.CreateKnativeRoute(namespace, route)
}

func UpdateRoute(fcClient *k8s.FcClient, alias *model.FuncAlias) (*kapiV1.Route, error) {
    namespace := ksvc.GetAliasNamespace(alias.AccountId, alias.GroupName)
    name := alias.FuncName + "-" + alias.AliasName
    route, err := fcClient.GetKnativeRoute(namespace, name)
    if err != nil {
        _ = logger.Error("UpdateRoute: get route error, %v", err)
        return nil, err
    }
    traffic, err := getTraffic(fcClient, alias)
    if err != nil {
        return nil, err
    }
    if !reflect.DeepEqual(route.Spec.Traffic, traffic) {
        route.Spec.Traffic = traffic
        return fcClient.UpdateKnativeRoute(namespace, route)
    }
    return route, nil
}

func DeleteRoute(fcClient *k8s.FcClient, alias *model.FuncAlias) error {
    namespace := ksvc.GetAliasNamespace(alias.AccountId, alias.GroupName)
    name := alias.FuncName + "-" + alias.AliasName
    err := fcClient.DeleteKnativeRoute(namespace, name)
    if err != nil {
        if !strings.Contains(err.Error(), "not found") {
            _ = logger.Error("DeleteRoute: delete route error %s", err.Error())
            return err
        }
    }
    return nil
}

func DeleteFuncRoute(fcClient *k8s.FcClient, functionInfo *model.FuncInfo) error {
    namespace := ksvc.GetFunctionNamespace(functionInfo.A5tId, functionInfo.GroupName)
    labelSelector := fmt.Sprintf("%s=%s", "function", functionInfo.FunctionName)
    err := fcClient.DeleteKnativeRouteByLabel(namespace, labelSelector)
    if err != nil {
        _ = logger.Error("DeleteFuncRoute: delete route error %s", err.Error())
        return err
    }
    return nil
}

func getTraffic(fcClient *k8s.FcClient, alias *model.FuncAlias) ([]kapiV1.TrafficTarget, error) {
    latestRevision := false
    namespace := ksvc.GetAliasNamespace(alias.AccountId, alias.GroupName)
    var traffic []kapiV1.TrafficTarget
    for _, rule := range alias.TrafficRule.Traffic {
        labelSelector := fmt.Sprintf("%s=%s,%s=%s", model.VersionLabelKey, rule.VersionName,
            model.FunctionNameLabelKey, alias.FuncName)
        revisionList, err := fcClient.GetKnativeRevisionList(namespace, labelSelector)
        if err != nil || len(revisionList.Items) == 0 {
            _ = logger.Error("CreateRoute: get revision list error, %v or len is 0", err)
            return nil, errors.New(fmt.Sprintf("get revision list error %v", err))
        }
        weight := int64(rule.VersionWeight)
        ruleTraffic := kapiV1.TrafficTarget{
            RevisionName:   revisionList.Items[0].Name,
            LatestRevision: &latestRevision,
            Percent:        &weight,
        }
        traffic = append(traffic, ruleTraffic)
    }
    return traffic, nil
}
